<?php

/**
 * Author: ChenGuangHui
 * Email：13035809409@163.com
 * Date Time: 2021/7/22 14:11
 */


namespace App\Logic\Material;


use App\Enums\HttpCode;
use App\Logic\CommLogic;
use App\Logic\Common\BaseLogic;
use App\Models\Material\Material;
use App\Models\Material\MaterialDir;
use App\Services\Upload\AliyunService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Storage;
use ZipArchive;

class MaterialLogic extends CommLogic
{
    /**
     * @return mixed
     */
    public function tree()
    {
        $dir = MaterialDir::query()
            ->get();
        if (!empty($dir)) {
            $dir = $this->_getTree($dir, 0);
        }
        return $dir ?? [];
    }

    /**
     * @param $dir
     * @param $parentId
     * @return array
     */
    protected function _getTree($dir, $parentId)
    {
        $tree = [];
        foreach ($dir as $d) {
            if ($d->parent_id == $parentId) {
                $data = $this->_getTree($dir, $d->id);
                if (!empty($data)) {
                    $d->children = $data;
                }
                $tree[] = $d;
            }
        }
        return $tree;
    }

    /**
     * @param $params
     * @return array
     */
    public function lists($params)
    {
        $materialDir = MaterialDir::query()
            ->where('parent_id', $params['dir_id'])
            ->orderByDesc('created_at')
            ->get()
            ->toArray();

        if (empty($materialDir)) return [];

        $material = Material::query()
            ->where('dir_id', $params['dir_id'])
            ->orderByDesc('created_at')
            ->get()
            ->toArray();
        foreach ($material as &$item) {
            $item['type'] = 1;
            $item['size'] = formatBytes($item['size']);
        }
        $data = array_merge($materialDir, $material);
        return collect($data)->sortByDesc('sort')->all();
    }

    /**
     * 创建文件夹
     * 
     * @author ChenGuangHui
     * @dateTime 2022-06-25
     * @param [type] $params
     */
    public function dir($params)
    {
        $parentId = $params['parent_id'] ?? 0;
        $material = MaterialDir::query()->where('name', $params['name'])->where('parent_id', $parentId)->first();
        abort_if(!empty($material), HttpCode::FORBIDDEN, '文件夹已存在！');
        $params = [
            'name' => $params['name'],
            'parent_id' => $parentId,
        ];
        return MaterialDir::query()->create($params);
    }

    /**
     * 新建文件夹、上传素材
     * @param Request $request
     * @return \App\Models\Model|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model
     * @throws \App\Exceptions\RJsonError
     */
    public function store(Request $request)
    {
        $lockName = 'material_store_' . auth('api')->id();
        $lock = \Cache::lock($lockName, 5);
        abort_if(!$lock->get(), HttpCode::TOO_MANY_REQUESTS, '请勿重复操作！');
        abort_unless($request->hasFile('file'), 500, '文件不合法！');
        $response = array();
        foreach ($request->file('file') as $file) {
            abort_if(!$file->isValid(), HttpCode::FORBIDDEN, '上传失败！');
            // 调用公共上传模块
            $upload = (new BaseLogic())->upload($file, array(
                'file_path' => 'material/tmp',
                'extension' => $file->extension(),
                'original_name' => $file->getClientOriginalName(),
            ));
            $params = [
                'size' => $upload['file_size'],
                'ext' => $file->extension(),
                'name' => $upload['original_name'],
                'path' => $upload['file_url'],
                'dir_id' => $request->get('dir_id', 0),
                'hash' => $upload['hash'],
            ];
            $data = Material::query()->create($params);
            $response[] = $data->toArray();
        }
        return $response;
    }

    /**
     * @param $params
     * @param $id
     * @return bool|int
     */
    public function update($params, $id)
    {
        $lockName = 'material_update_' . auth('api')->id();
        $lock = \Cache::lock($lockName, 5);
        abort_if(!$lock->get(), HttpCode::TOO_MANY_REQUESTS, '请勿重复操作！');
        if ($params['type'] == 1) {
            $material = Material::query()->where('id', $id)->first();
            abort_if(empty($material), HttpCode::FORBIDDEN, '文件不存在！');
            $material->update(['name' => $params['name']]);
        } else {
            $material = MaterialDir::query()->where('id', $id)->first();
            abort_if(empty($material), HttpCode::FORBIDDEN, '文件夹不存在！');
            $material = MaterialDir::query()->where('name', $params['name'])->where('parent_id', $material->parent_id)->first();
            abort_if(!empty($material), HttpCode::FORBIDDEN, '文件夹已存在！');
            MaterialDir::query()->where('id', $id)->update(['name' => $params['name']]);
        }
        return true;
    }

    /**
     * @param $params
     * @param $id
     * @return bool|mixed|null
     */
    public function destroy($params, $id)
    {
        if ($params['type'] == 1) {
            $data = Material::query()->where('id', $id)->first();
        } else {
            $data = MaterialDir::query()->where('id', $id)->first();
        }
        abort_if(empty($data), HttpCode::FORBIDDEN, '文件不存在！');
        return $data->delete();
    }

    /**
     * @param $params
     * @param $id
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse|\Symfony\Component\HttpFoundation\StreamedResponse
     */
    public function dowload($params, $id)
    {
        if ($params['type'] == 1) {
            $material = Material::query()->where('id', $id)->first();
        } else {
            $material = MaterialDir::query()->with('children')->where('id', $id)->first();
        }
        abort_if(empty($material), HttpCode::FORBIDDEN, '文件不存在！');
        if ($params['type'] == 1) {
            return Response::download($material->path);
        }
        // 压缩文件夹
        $this->_child($material);
        $dir = storage_path('file');
        $dir_path = storage_path($material->name . '.zip');
        $zip = new ZipArchive();
        abort_if(!is_dir($dir), HttpCode::FORBIDDEN, '文件失踪了！');
        if ($dh = opendir($dir)) {
            $zip->open($dir_path, ZipArchive::CREATE);
            while (($file = readdir($dh)) !== false) {
                if (in_array($file, ['.', '..',])) continue;
                $zip->addFile($dir . '/' . $file, $file);
            }
            $zip->close();
            closedir($dh);
        }
        return Storage::disk('public')->download($dir_path);
    }

    /**
     * 生成本地文件夹
     * @param $dirs
     * @param string $path
     */
    private function _child($dirs, $path = '')
    {
        $dir_path = $path . '/' . $dirs->name;
        $materials = Material::query()->where('dir_id', $dirs->id)->get();
        foreach ($materials as $material) {
            Storage::disk('public')->putFile($dir_path, $material->path);
        }
        if (!empty($dirs->children)) {
            $this->_child($dirs->children, $dir_path);
        }
    }
}
